Skip to content

[codex] WLED: use repo-aware release checks for upgrades - #172481

Open
LordMike wants to merge 5 commits into
home-assistant:devfrom
LordMike:update-wled-custom-fw
Open

[codex] WLED: use repo-aware release checks for upgrades#172481
LordMike wants to merge 5 commits into
home-assistant:devfrom
LordMike:update-wled-custom-fw

Conversation

@LordMike

@LordMike LordMike commented May 28, 2026

Copy link
Copy Markdown
Contributor

Breaking change

Proposed change

WLED upgrade checks now use repository-aware release lookup through WLEDReleases, default to wled/WLED when the device does not report a repository, deduplicate release lookups per unique repo, and upgrade using the repo and release reported by the device API.

This PR depends on frenck/python-wled#2078 and is opened to allow review from @mik-laj.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Deprecation (breaking change to happen in the future)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

Checklist

  • I understand the code I am submitting and can explain how it works.
  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • I have followed the perfect PR recommendations
  • The code has been formatted using Ruff (ruff format homeassistant tests)
  • Tests have been added to verify that the new code works.
  • Any generated code has been carefully reviewed for correctness and compliance with project standards.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running: python3 -m script.gen_requirements_all.
  • For the updated dependencies a diff between library versions and ideally a link to the changelog/release notes is added to the PR description.

To help with the load of incoming pull requests:

Copilot AI review requested due to automatic review settings May 28, 2026 17:56
@home-assistant home-assistant Bot added bugfix cla-signed has-tests integration: wled Top 100 Integration is ranked within the top 100 by usage Top 200 Integration is ranked within the top 200 by usage labels May 28, 2026
@home-assistant

Copy link
Copy Markdown
Contributor

Hey there @frenck, @mik-laj, mind taking a look at this pull request as it has been labeled with an integration (wled) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of wled can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant mark-draft Mark the pull request as draft.
  • @home-assistant ready-for-review Remove the draft status from the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign wled Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant update-branch Update the pull request branch with the base branch.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) on the pull request.

@LordMike

Copy link
Copy Markdown
Contributor Author

Note - this is not entirely ready. The PR is still draft for that reason.

Discussion will continue in frenck/python-wled#2078 until that has been merged.

return True


async def async_get_releases_coordinator(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit problematic because this coordinator is never stopped when a user stops using the fork.

I'm wondering if it would be possible to update the coordinator to check which repositories the user is using and download data for all the repositories the user is currently using.

What do you think about this?

@mik-laj mik-laj May 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another solution is to register the repository in the release coordinator in async_setup_entry and then unregister it in the async_unload_entry function.

hass.data[WLED_KEY].register_repo(entry_id, coordinator.data.info.repo)
hass.data[WLED_KEY].unregister_repo(entry_id)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I see it though, the release coordinator remains in memory, yes (and we could definitely prune that) - but we're not actively polling the repo there. So if you add a device A, with repo A - and remove device A. Then repo A remains, but is not polled. The DataUpdateCoordinator base operates with listeners (each update entity listens), and when the last listener disappears, which it hopefully does, DataUpdateCoordinator stops polling.

I'll see if we can't clean out the dict regardless.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you on to making WLEDReleasesDataUpdateCoordinator able to manage multiple repositories in one instance?

@LordMike LordMike May 28, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I looked into blindly going for entry setup/teardown, but it would introduce extra bookkeeping. On entry_setup ( a single device), we create the coordinator if not existing. But on teardown, we'd have to start reviewing if the coordinator is still in use.

It seems unlikely to be a problem, leaving hte coordinator around after the device has disappeared. It only lasts till next restart of the HA instance. And it really is only 1 instance per unique repository - so in practice its like.. at most 2..

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, a drawback here is that:

  • there is one release coordinator, and it makes N requests on updates - if any 1/N requests fail, the entire check fails
  • if an update entity forces a recheck, it will recheck all repos

I'm partial to the one instance per repo instead, keep it lean.. but then try to solve for cleanup - either the temporary bit like disabling the update entity, or the more permanent bit that is removing a WLED device (entry) entirely. It could be solved by a set of entry_ids in each release coordinator, and when that set is empty, we remove it.

The release coordinator already tracks subscriptions, which each update entity uses. We could in our WLED release coordinator, expose the count of subscriptions, and if after removal this becomes 0, we clean up the instance entirely. Hopefully we can then tweak disabling of update entities to unsubscribe, which in turn will make stuff auto-cleanup.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is something on .. what if we have 2 wled devices (same repo), and we do a force update on all their update entities at the same time. We will then do two forceful data updates, which means two queries for releases, parsing of those, paginating those, and so on..

If you had 10 or 100 wled devices, we might hit GH rate limits, even.

... something like a time limit on rechecks? "minimum 60s since last check" -style.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is one release coordinator, and it makes N requests on updates - if any 1/N requests fail, the entire check fails

We can add better error handling similarly to what is done in the system monitor integration.

if self.update_subscribers[("disks", argument)] or self._initial_update:
try:
usage: sdiskusage = self._psutil.disk_usage(argument)
_LOGGER.debug("sdiskusagefor %s: %s", argument, usage)
except PermissionError as err:
_LOGGER.warning(
"No permission to access %s, error %s", argument, err
)
except OSError as err:
_LOGGER.warning("OS error for %s, error %s", argument, err)
else:
disks[argument] = usage

if an update entity forces a recheck, it will recheck all repos

I think this is a minor issue because at most the user will have more up-to-date data.

There is something on .. what if we have 2 wled devices (same repo), and we do a force update on all their update entities at the same time.

I think that the coordinator debouncer will work here, it will prevent the same data from being downloaded multiple times in a short period of time.

I'm partial to the one instance per repo instead, keep it lean.. but then try to solve for cleanup - either the temporary bit like disabling the update entity, or the more permanent bit that is removing a WLED device (entry) entirely. It could be solved by a set of entry_ids in each release coordinator, and when that set is empty, we remove it.

I'm not sure what that would look like, but we could try to implement it. I proposed my solution because it sounded relatively simple to me. It requires the least amount of code changes to get it working now. I will open a PR with my proposal so that we can see what it looks like in full and then we can compare.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a draft PR: mik-laj#1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll move closer to a single instance of update coordinator, and then tracking repos in it.

@mik-laj

mik-laj commented May 28, 2026

Copy link
Copy Markdown
Contributor

.. I Pushed a new release build on my wled repo, firmwares were built. I restarted HA, because apparently its not possible for forcibly check for an update with homeassistant.update_entity.

Good catch. We need to override async_update and trigger release coordinator refresh, because now the main coordinator is triggered.

async def async_update(self) -> None:
"""Update the entity.
Only used by the generic entity update service.
"""
# Ignore manual update requests if the entity is disabled
if not self.enabled:
return
await self.coordinator.async_request_refresh()

It would be good to fix this in a separate PR.

@LordMike

Copy link
Copy Markdown
Contributor Author

I also reconfigured my wled device, in the hopes it would trigger a recheck.. And then the config page gave me a string placeholder like "reconfigure_succeeded".. Looks like the config flows could also need a hand.. :P

@LordMike

LordMike commented May 28, 2026

Copy link
Copy Markdown
Contributor Author

It would be good to fix this in a separate PR.

Things we could fix:

  • update_entity to do update checks
  • config flow texts
  • reduce the update check interval - 3 hours is a bit too often, no? Github is a free service, and hammering them with 10k requests/hour, every hour, all day - just to probe latest release, an event that happens a few times a year for stable.. If anything, let it be an option somewhere - so those wanting unstables quickly can do so... oorr, use the other fix to let users set an automation that does update_entity on their own schedule.
  • some fields are never set, like release_summary or release_notes - I've amended the python-wled PR with this note as it needs to expose the release body text(s).
  • a configurable ability per device, to track stable or unstable releases. Today, if a device is on a prerelease, the upgrader will allow prerelease builds if they're newest. But if the newest is stable, the user mgiht end up on a stable firmware, and then not go back to a newer unstable. A setting per wled device could be made to indicate "follow prerelease builds" to allow prerelease any day.

@mik-laj

mik-laj commented May 30, 2026

Copy link
Copy Markdown
Contributor

Good list - a few thoughts:

update_entity: Already handled in #172517.

Config flow texts: I haven't personally observed this issue. Could you double-check that all translation files are compiled/up-to-date on your end?

Update interval: The 3h interval supports both stable and nightly releases in the same coordinator, so it isn't just probing for once-a-year stable events - it's 8 requests per day per repo. That said, I agree any interval above 1h is reasonable. With update_entity now triggering a release refresh (#172517), users who want faster checks can trigger it manually or via automation. If we now add support for multiple repos we can increase this to 6 hours, but that's a minor problem. I wouldn't worry about it at all.

release_summary / release_notes: Good idea. I think we need a separate PR to python-wled that adds this.

Stable vs. prerelease tracking: Good point. If a device is running a prerelease, we should probably keep offering prerelease updates rather than silently landing on stable. There's a related discussion in #160270 - worth aligning with whatever comes out of that.

@LordMike

Copy link
Copy Markdown
Contributor Author

Update interval: The 3h interval supports both stable and nightly releases in the same coordinator, so it isn't just probing for once-a-year stable events - it's 8 requests per day per repo. That said, I agree any interval above 1h is reasonable. With update_entity now triggering a release refresh (#172517), users who want faster checks can trigger it manually or via automation. If we now add support for multiple repos we can increase this to 6 hours, but that's a minor problem. I wouldn't worry about it at all.

Quick note on this. HA data shows 34k installations of WLED. Lets assume close to 100% have 1+ devices, on currently one repository. Thats 34k req/3h, or ~10k/h.

I've acquired stable release dates in this table:

Release Date Gap from previous stable
v16.0.0 2026-05-03 50 days
v0.15.4 2026-03-14 100 days
v0.15.3 2025-12-04 5 days
v0.15.2 2025-11-29 121 days
v0.15.1 2025-07-31 233 days
v0.15.0 2024-12-10 206 days
v0.14.4 2024-05-18 44 days from 0.14.3

That's potentially, on average (assuming stable users) 100 days of 10k req/h, before a "hit" is made.

Beyond this, and the whole "lets hammer a free service like Github" thing, there's these points for slower updates, like checking once daily or once every few days:

  • regular users will receive an update, at some point, which has not been retracted. If a bug is found in a major WLED release, potentially all users will have updated to it quickly. If its artificially staggered out, then the chance of a random user getting the bugged release before a hotfix or retraction, is lower.
  • the whole supply chain thing - slower updates means fewer users are impacted if a malicious WLED release is made, until its discovered / retracted

@mik-laj

mik-laj commented May 30, 2026

Copy link
Copy Markdown
Contributor

Beyond this, and the whole "lets hammer a free service like Github" thing, there's these points for slower updates, like checking once daily or once every few days:

10k/h requests is nothing for GitHub. Really. But we can bump it now to one day if we're adding support for multiple repos. It's best to do that in a separate PR so we can figure out what the best value is in separate thread.

@LordMike

Copy link
Copy Markdown
Contributor Author

Stable vs. prerelease tracking: Good point. If a device is running a prerelease, we should probably keep offering prerelease updates rather than silently landing on stable. There's a related discussion in #160270 - worth aligning with whatever comes out of that.

That PR was closed, so no further discussion is made. But if I read it right, the chosen option is essentially what is done today - the HA wled integration checks the current fw, and then picks the newest of the allowed set of (stable, unstable, nightly).. with the natural tendency to move towards stable.

It is possible to make settings per subenty, so a quick cogwheel could be added to show this dropdown of release track to follow. Users wouldn't have to do anything, on device setup or first run of this new code, the current firmware version could be determined and then the track stored in the subentry setting. Then for all future runs, it just is what it should be. A user may then change it to f.ex. "stable", or "stable and beta and nightly", or ...

@LordMike

LordMike commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

I've changed the PR to revert to a single WLED Update Coordinator, which then holds the full set of release infos in a dict. Steps have been taken to ensure we track required repos properly, and that should github fail, we're not reverting back to no data at all.

@LordMike
LordMike marked this pull request as ready for review June 4, 2026 18:26
@LordMike
LordMike requested a review from frenck as a code owner June 4, 2026 18:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix cla-signed has-tests integration: wled Quality Scale: platinum Top 100 Integration is ranked within the top 100 by usage Top 200 Integration is ranked within the top 200 by usage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants